/**
 * 
 */
package game.model;

import game.render.Canvas;
import game.render.Font;
import game.render.Res;

import javax.microedition.lcdui.Graphics;

/**
 * @author Quynh Lam
 * 
 */
public class Char extends LiveActor {
    public static final int SKILL_TYPE_CLOSE = 0;
    public static final int SKILL_TYPE_FAR = 1;
    public static final short SKILLTYPE[] = { 0, 1, 1, 1, 1, 1 };// By ID
    public static final short SKILLRANGE[] = { 20, 100, 150, 80, 120, 150 };// By ID
    public static final short SKILLDELAY[] = { 1000, 1500, 2000, 1500, 1000, 2000 };// milisec
    public long timeLastUseSkill;
    public long delayLastSkill;
    public boolean justStopFromRun = false;
    public int frame;
    public LiveActor attackTarget;
    public int speed;
    public short act, p1, p2, p3, p4, xTo, yTo, weapon_frame = -1, skillID, skillType, skillRange;
    public static final int A_STAND = 0;
    public static final int A_RUN = 1;
    public static final short A_ATTACK = 2;
    //
    public static final int DOWN = 0;
    public static final int UP = 1;
    public static final int LEFT = 2;
    public static final int RIGHT = 3;
    public static final int REAL_FRAME_EACH_SIZE = 5;
    public int currentBody, currentLeg, currentHat, currentHead;
    private int attkPower;
    // Frame map with real Frame
    // FRAME_MAP[Frame][info:legf,bodyf,bodydx,bodydy,headf,headdx,headdy]
    public static int FRAME_MAP[][] = {//
    //
            { 0, 0, 12, 26, 0 },// 0 Stand1
            //
            { 1, 1, 12, 26, 0 },// 1 Run
            { 2, 0, 12, 26, 0 },// 2
            { 3, 2, 12, 26, 0 },// 3
            { 4, 0, 12, 26, 0 },// 4
            //
            { 0, 0, 12, 25, 0 },// 5 Stand2
            //
            { 5, 3, 12, 26, 0 },// 6 Attak1
            { 6, 4, 12, 26, 0 },// 7 Attak2
    };
    public static int HEAD_D[][][] = {//
    //
            { { 7, 36 }, { 7, 36 }, { 7, 36 }, { 7, 36 } },//
            //
            { { 7, 35 }, { 7, 35 }, { 7, 35 }, { 7, 35 } },//
            { { 7, 36 }, { 7, 36 }, { 7, 36 }, { 7, 36 } },//
            { { 7, 35 }, { 7, 35 }, { 7, 35 }, { 7, 35 } },//
            { { 7, 36 }, { 7, 36 }, { 7, 36 }, { 7, 36 } },//
            //
            { { 7, 35 }, { 7, 35 }, { 7, 35 }, { 7, 35 } },//
            //
            { { 6, 33 }, { 9, 34 }, { 5, 33 }, { 8, 33 } },//
            { { 6, 30 }, { 7, 32 }, { 11, 31 }, { 4, 31 } },//
    //
    };
    public static final int[] RUNFRAME = { 1, 2, 3, 4 };

    public Char() {
        type = 0;
        speed = 2;
        centerX = 12;
        centerY = 12;
        height = 32;
    }

    public void moveTo(short xTo, short yTo) {
        this.xTo = xTo;
        this.yTo = yTo;
        if (x == xTo && y == yTo) {
            if (act == A_ATTACK)
                return;
            act = A_STAND;
        } else {
            weapon_frame = -1;
            act = A_RUN;
        }
    }

    public static final int NEXTX[] = { 0, 0, -1, 1 };
    public static final int NEXTY[] = { 1, -1, 0, 0 };

    public void update() {
        if (realHPSyncTime > 0) {
            realHPSyncTime--;
            if (realHPSyncTime == 0) {
                if (realHP < 0)
                    realHP = 0;
                hp = realHP;
            }
        }
        switch (act) {
        case A_STAND:
            p1++;
            if (p1 > 10)
                p1 = 0;
            if (p1 > 6)
                frame = 5;
            else
                frame = 0;
            break;
        case A_ATTACK:
            switch (skillID) {
            case 0:
                updateAxeAttack();
                break;
            case 1:
                updateAttack_HOA();
                break;
            case 2:
                updateAttack_KIM();
                break;
            case 3:
                updateAttack_THO();
                break;
            case 4:
                updateAttack_THUY();
                break;
            case 5:
                updateAttack_MOC();
                break;
            default:
                break;
            }

            break;
        case A_RUN:
            p1++;
            if (p1 > 7)
                p1 = 0;
            frame = RUNFRAME[(p1 >> 1)];
            boolean isMatchX = false,
            isMatchY = false;
            int dx1 = Canvas.abs(x - xTo);
            int dy1 = Canvas.abs(y - yTo);
            int spd = this.speed;
            if (dx1 > 100 || dy1 > 100)
                spd = this.speed + 4;
            else if (dx1 > 70 || dy1 > 70)
                spd = this.speed + 3;
            else if (dx1 > 50 || dy1 > 50)
                spd = this.speed + 2;
            else if (dx1 > 30 || dy1 > 30)
                spd = this.speed + 1;

            if (dx1 <= spd) {
                x = xTo;
                isMatchX = true;
            }
            if (dy1 < spd) {
                y = yTo;
                isMatchY = true;
            }
            if (isMatchX && isMatchY) {
                p1 = p2 = p3 = 0;
                act = A_STAND;
                justStopFromRun = true;
                break;
            }

            if (x < xTo) {
                x += spd;
                dir = RIGHT;
            } else if (x > xTo) {
                x -= spd;
                dir = LEFT;
            } else if (y > yTo) {
                y -= spd;
                dir = UP;
            } else if (y < yTo) {
                y += spd;
                dir = DOWN;
            }
            break;
        default:
            break;
        }
    }

    /**
     * 
     */
    private void updateAttack_THO() {
        frame = 6;
        if (p1 == 1)
            EffectManager.lowEffects.addElement(new Effect(x, y - 15, 5));
        if (p1 > 15) {
            act = A_STAND;
            p1 = p2 = p3 = 0;
        } else if (p1 == 5) {
            Canvas.gameScr.startNewArrow(2, this, attackTarget, x, y - 15, attkPower);
            frame = 7;
        } else if (p1 > 3) {
            frame = 7;
        } else if (p1 > 1) {
            frame = 6;
        } else {
            frame = 6;
        }
        p1++;

    }

    private void updateAttack_HOA() {
        frame = 6;
        if (p1 == 1)
            EffectManager.lowEffects.addElement(new Effect(x, y, 0));
        if (p1 > 15) {
            act = A_STAND;
            p1 = p2 = p3 = 0;
        } else if (p1 == 5) {
            Canvas.gameScr.startNewArrow(0, this, attackTarget, x, y - 15, attkPower);
            frame = 7;
        } else if (p1 > 3) {
            frame = 7;
        } else if (p1 > 1) {
            frame = 6;
        } else {
            frame = 6;
        }
        p1++;

    }

    private void updateAttack_THUY() {
        frame = 6;
        if (p1 == 1)
            EffectManager.lowEffects.addElement(new Effect(x, y - 15, 7));
        if (p1 > 10) {
            act = A_STAND;
            p1 = p2 = p3 = 0;
        } else if (p1 == 5) {
            Canvas.gameScr.startNewArrow(3, this, attackTarget, x, y - 15, attkPower);
            frame = 7;
        } else if (p1 > 3) {
            frame = 7;
        } else if (p1 > 1) {
            frame = 6;
        } else {
            frame = 6;
        }
        p1++;

    }

    private void updateAttack_KIM() {
        frame = 6;
        if (p1 == 1)
            EffectManager.lowEffects.addElement(new Effect(x, y - 15, 3));
        if (p1 > 7) {
            act = A_STAND;
            p1 = p2 = p3 = 0;
        } else if (p1 == 5) {
            Canvas.gameScr.startNewArrow(1, this, attackTarget, x, y - 15, attkPower);
            frame = 7;
        } else if (p1 > 3) {
            frame = 7;
        } else if (p1 > 1) {
            frame = 6;
        } else {
            frame = 6;
        }
        p1++;
    }

    private void updateAttack_MOC() {
        frame = 6;
        if (p1 == 1)
            EffectManager.lowEffects.addElement(new Effect(x, y - 15, 9));
        if (p1 > 10) {
            act = A_STAND;
            p1 = p2 = p3 = 0;
        } else if (p1 == 5) {
            Canvas.gameScr.startNewArrow(4, this, attackTarget, x, y - 15, attkPower);
            frame = 7;
        } else if (p1 > 3) {
            frame = 7;
        } else if (p1 > 1) {
            frame = 6;
        } else {
            frame = 6;
        }
        p1++;
    }

    /**
     * 
     */
    private void updateAxeAttack() {
        frame = 6;
        if (p1 > 7) {
            act = A_STAND;
            p1 = p2 = p3 = 0;
            weapon_frame = -1;
        } else if (p1 > 5) {
            if (attackTarget != null) {
                if (attackTarget.type == 1) {
                    ((Monster) attackTarget).jump();
                }
                attackTarget.realHPSyncTime = 2;
            }
            EffectManager.lowEffects.addElement(new Effect(x + NEXTX[dir] * (skillRange), y + NEXTY[dir] * (skillRange), 0));
            frame = 7;
            weapon_frame = 3;
        } else if (p1 > 3) {
            frame = 7;
            weapon_frame = 2;
        } else if (p1 > 1) {
            frame = 6;
            weapon_frame = 1;
        } else {
            frame = 6;
            weapon_frame = 0;
        }
        p1++;
    }

    public void paint(Graphics g) {

        int realLegFrame = 7 * dir + FRAME_MAP[frame][0];
        g.drawRegion(Res.imgCharLeg[currentLeg], 0, realLegFrame * 16, 24, 16, 0, x - centerX, y - centerY, 0);
        int realBodyFrame = 5 * dir + FRAME_MAP[frame][1];
        g.drawRegion(Res.imgCharBody[currentBody], 0, realBodyFrame * 30, 24, 30, 0, x - FRAME_MAP[frame][2], y - FRAME_MAP[frame][3], 0);
        int realHeadFrame = 1 * dir + FRAME_MAP[frame][4];
        g.drawRegion(Res.imgCharHead[currentHead], 0, realHeadFrame * 24, 12, 24, 0, x - HEAD_D[frame][dir][0], y - HEAD_D[frame][dir][1], 0);
        g.drawRegion(Res.imgCharHat[currentHat], 0, realHeadFrame * 17, 18, 18, 0, x - HEAD_D[frame][dir][0], y - 2 - HEAD_D[frame][dir][1], 0);
        if (weapon_frame != -1) {

            g.drawRegion(Res.imgSkill[skillID],//
                    Res.skillInfo[skillID][dir][weapon_frame][0],//
                    Res.skillInfo[skillID][dir][weapon_frame][1], //
                    Res.skillInfo[skillID][dir][weapon_frame][2],//
                    Res.skillInfo[skillID][dir][weapon_frame][3],//
                    0,//
                    x + Res.skillInfo[skillID][dir][weapon_frame][4],//
                    y + Res.skillInfo[skillID][dir][weapon_frame][5],//
                    0);
        }
        if (name != null)
            Font.drawFontBString(g, name, x, y - 50, 2);
        paintHPBar(g);
    }

    /**
     * @param g
     */
    private void paintHPBar(Graphics g) {
        if (maxhp == 0)
            return;
        int hpbLeft = x - 10;
        int hpbTop = y - 36;
        int hpbWidth = 20;
        int hpbHeight = 3; // Include 2 pixel border
        g.setColor(0);
        g.fillRect(hpbLeft, hpbTop, hpbWidth, hpbHeight);
        g.setColor(0x33000);
        g.fillRect(hpbLeft + 1, hpbTop + 1, hpbWidth - 2, hpbHeight - 2);
        int hpInPixel = hp * (hpbWidth - 2) / maxhp;
        g.setColor(0xDD000);
        g.fillRect(hpbLeft + 1, hpbTop + 1, hpInPixel, hpbHeight - 2);
    }

    /*
     * (non-Javadoc)
     * 
     * @see game.model.Actor#setPosTo()
     */
    public void setPosTo(short x, short y) {
        moveTo(x, y);

    }

    /**
     * @param charInfo
     */
    public void setCurrentSkill(short skill) {
        skillID = skill;
        skillType = SKILLTYPE[skillID];
        skillRange = SKILLRANGE[skillID];
        delayLastSkill = SKILLDELAY[skillID];
    }

    public void setInfo(CharInfo charInfo) {
        xTo = x = charInfo.x;
        yTo = y = charInfo.y;
        name = charInfo.name;
        realHP = hp = charInfo.hp;
        maxhp = charInfo.maxhp;
        setCurrentSkill(charInfo.skillID);
    }

    /**
     * 
     */
    public void startAttack(LiveActor target, int power, short skillID) {
        setCurrentSkill(skillID);
        this.attackTarget = target;
        timeLastUseSkill = System.currentTimeMillis();
        act = A_ATTACK;
        attkPower = power;
        p1 = p2 = p3 = 0;
    }
}
